package cn.mw.cmdb.entity;

import cn.hutool.core.util.ReflectUtil;
import cn.mw.cmdb.enums.TableViewTypeEnum;
import cn.mw.cmdb.param.TemplateSearchParam;
import cn.mw.cmdb.processor.MonitorValue;
import cn.mw.cmdb.service.ServiceChoose;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.util.DataCreateInfo;
import cn.mw.components.mongodb.anno.AutoId;
import cn.mw.components.mongodb.anno.CMDBProperty;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.microMonitorCommon.api.cmdb.TableIdEnum;
import cn.mw.microMonitorCommon.api.cmdb.TreeView;
import cn.mw.scanengine.entity.ScanEngineInfoFetch;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.common.base.Strings;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;

@Data
@Document("mw_cmdbmd_instance")
@JsonIgnoreProperties(ignoreUnknown = true)
@EqualsAndHashCode
public class InstanceInfo extends DataAuth implements MonitorValue, ServiceChoose, TreeView, DataCreateInfo
        , ScanEngineInfoFetch, Serializable {
    @Serial
    private static final long serialVersionUID = 1L;

    public static final String SearchPrefix = "data";

    @Schema(description = "实例Id")
    @CMDBProperty(searchType = PropertyTypeString.ID, searchPrefix = "_", isShow = true)
    @AutoId
    private String id;

    @Indexed
    @Schema(description = "实例名称")
    @CMDBProperty(searchType = PropertyTypeString.ID, keywordSearch = true)
    private String instanceName;

    @Indexed
    @Schema(description = "模型Id")
    @CMDBProperty(searchType = PropertyTypeString.ID, isShow = true)
    private String modelId;

    @Schema(description = "金融元父模型id")
    @CMDBProperty(searchType = PropertyTypeString.ID, isShow = true)
    private String financeParentId;

    //为了使用注解来生成查询,因此添加拥有该字段信息的时候,会与data字段中的重复
    //todo 还需要想更好的方式来优化，避免重复
    @Schema(description = "IP地址")
    @CMDBProperty(searchType = PropertyTypeString.ID, keywordSearch = true)
    private String inBandIp;

    // singleton, batch
    @CMDBProperty(searchType = PropertyTypeString.ID)
    private String taskType;

    // 当前扫描进度,batch类型才有
    @CMDBProperty(searchType = PropertyTypeInt.ID)
    private Integer progress;

    // 执行状态
    @CMDBProperty(searchType = PropertyTypeString.ID, keywordSearch = true)
    private String status;

    //分组id
    @CMDBProperty(searchType = PropertyTypeString.ID, isShow = true)
    @Schema(description = "分组id")
    private String groupId;

    //为了使用注解来生成查询,因此添加拥有该字段信息的时候,会与data字段中的重复
    //todo 还需要想更好的方式来优化，避免重复
    //品牌id
    @CMDBProperty(searchType = PropertyTypeString.ID, isShow = true)
    @Schema(description = "品牌id")
    private String brandId;

    //业务系统Id
    @CMDBProperty(searchType = PropertyTypeString.ID, isShow = true)
    @Schema(description = "业务系统Id")
    private String businessId;

    //资产状态
    @CMDBProperty(searchType = PropertyTypeString.ID, isShow = true, keywordSearch = true)
    @Schema(description = "资产状态")
    private String itemAssetsStatus;

    @CMDBProperty(searchType = PropertyTypeTime.ID)
    @Schema(description = "实例过期时间")
    protected Date expireTime;

    @CMDBProperty(searchType = PropertyTypeString.ID, keywordSearch = true)
    @Schema(description = "创建人")
    protected Long creater;

    @CMDBProperty(searchType = PropertyTypeTime.ID)
    @Schema(description = "创建时间")
    protected Date createTime;

    @CMDBProperty(searchType = PropertyTypeString.ID, keywordSearch = true)
    @Schema(description = "修改人")
    protected Long modifier;

    @CMDBProperty(searchType = PropertyTypeTime.ID)
    @Schema(description = "修改时间")
    protected Date modificationTime;

    @CMDBProperty(searchType = PropertyTypeList.ID, isShow = true)
    @Schema(description = "路径Id")
    private List<String> path;
    @CMDBProperty(logicDel = true, searchType = PropertyTypeList.ID)
    protected Boolean delFlag = false;
    @CMDBProperty
    private Map<String, Object> data = new HashMap<>();

    //设备指纹信息
    @CMDBProperty(searchType = PropertyTypeString.ID)
    private String deviceCode;

    //信息加密标识
    private boolean encryptSign;

    //是否自动设置资产编码code
    @Transient
    private boolean deviceCodeFlag;

    //纳管资产是否随机名称
    private Boolean randomNameFlag;


    @Override
    public Integer getProxyType() {
        return MonitorValue.super.getProxyType();
    }

    @Override
    public String getPollingEngine() {
        return MonitorValue.super.getPollingEngine();
    }

    @Override
    public void setEncrypt(boolean sign) {
        encryptSign = sign;
    }

    @Override
    public boolean getEncrypt() {
        return encryptSign;
    }

    @Override
    public Object getValue(String key) {

        Object value = data.get(key);
        //如果data中的数据为null或空字符串，使用instanceInfo赋值
        if (Strings.isNullOrEmpty(strValueConvert(value))) {
            value = ReflectUtil.getFieldValue(this, key);
            if(Strings.isNullOrEmpty(strValueConvert(value))){
                if(key!=null && key.contains(Prefix)){
                    String replace = key.replace(Prefix, "");
                    value = ReflectUtil.getFieldValue(this, replace);
                }
            }
            //如果instanceInfo中值未null，value设置为原始data中的数据
            if (value == null) {
                value = data.get(key);
            }
        }
        return value;
    }

    @Override
    public void removeField(String field){
        if(!Strings.isNullOrEmpty(field) && data!=null){
            data.remove(field);
        }
    }

    @Override
    public Object getDataValue(String key) {
        Object value = data.get(key);
        return value;
    }

    @Override
    public Object getEntityValue(String key) {
        Object value = ReflectUtil.getFieldValue(this, key);
        return value;
    }

    @Override
    public void setValue(String key, Object value) {
        data.put(key, value);
    }

    @Override
    public String getServiceId() {
        return InstanceServiceImpl.ID;
    }

    @Override
    public Object getParentId() {
//        if(null != path && path.size() > 0){
//            return path.get(path.size() - 1);
//        }
        return modelId;
    }

    @Override
    public String getItemName() {
        return instanceName;
    }

    @Override
    public String getType() {
        return TableIdEnum.instance.name();
    }

    @Override
    public String getViewType() {
        return TableViewTypeEnum.list.getCode();
    }

    @Override
    @JsonIgnore
    public List<String> getChildStatus() {
        return null;
    }

    @Override
    @JsonIgnore
    public void setChildStatus(List<String> status) {

    }


    public void fieldCheckMatch(){
        //设置实例名称
        if(!Strings.isNullOrEmpty(strValueConvert(getValue(InStanceNameKey)))){
            setInstanceName(strValueConvert(getValue(InStanceNameKey)));
            setValue(InStanceNameKey,strValueConvert(getValue(InStanceNameKey)));
        }
        //设置IP地址
        if(!Strings.isNullOrEmpty(strValueConvert(getValue(InBandIpKey)))){
            setInBandIp(strValueConvert(getValue(InBandIpKey)));
            setValue(InBandIpKey,strValueConvert(getValue(InBandIpKey)));
        }
        //设置厂商Id
        if(!Strings.isNullOrEmpty(strValueConvert(getValue(BrandKey))) && Strings.isNullOrEmpty(getBrandId())){
            setBrandId(strValueConvert(getValue(BrandKey)));
        }
        //设置厂商Id
        if(!Strings.isNullOrEmpty(getBrandId()) && Strings.isNullOrEmpty(strValueConvert(getValue(BrandKey)))){
            setValue(BrandKey,getBrandId());
        }
    }


    // 手动添加时，只能传模板名称、厂商、规格型号监控方式等信息，需匹配对应模板
    @JsonIgnore
    public TemplateSearchParam getTemplateSearchParam() {
        String templateName = getTemplateName();
        TemplateSearchParam searchParam = new TemplateSearchParam();
        if (Strings.isNullOrEmpty(templateName)) {
            return searchParam;
        }
        if (!Strings.isNullOrEmpty(getBrand())) {
            searchParam.addSubCondition(CMDBTool.getFieldName(ModelTemplateInfo::getBrandId)
                    , new SubCondition(CriteriaOpsType.is.name(), getBrand()));
        }
        if (!Strings.isNullOrEmpty(getSpecification())) {
            searchParam.addSubCondition(CMDBTool.getFieldName(ModelTemplateInfo::getSpecificationId)
                    , new SubCondition(CriteriaOpsType.is.name(), getSpecification()));
        }
        if ((getMonitorMode()) != null) {
            searchParam.addSubCondition(CMDBTool.getFieldName(ModelTemplateInfo::getMonitorMode)
                    , new SubCondition(CriteriaOpsType.is.name(), getMonitorMode()));
        }
        return searchParam;
    }
}
